/*
 * Copyright Iain Sproat, 2008
 * Based on code at http://www.freebase.com/view/guid/9202a8c04000641f80000000090e3aee
 *
 */
using System;
using FreeBase.Fluent;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Authentication;

using log4net;

namespace FreeBase
{
	public interface IFreebaseClient
	{
		string Read( string query );
		void Authenticate();
	}
	
	public class FreebaseClient : IFreebaseClient
	{
		private static string sandbox = "http://sandbox.freebase.com";
		private static string server = "http://freebase.com";
		private static string queryurl = "/api/service/mqlread";
		private static string path = "/api/account/login";
		private string user = string.Empty;
		private string pass = string.Empty;
		private static CookieContainer authCookies = null;
		private ILog logger = LogManager.GetLogger(typeof(FreebaseClient));
		
		private bool _useSandbox;

		public FreebaseClient(){}
		public FreebaseClient( string userName, string passWord )
		{
			if( string.IsNullOrEmpty( userName ) )
				throw new ArgumentNullException( "userName" );
			if( string.IsNullOrEmpty( passWord ) )
				throw new ArgumentNullException( "passWord" );
			
			this.user = userName;
			this.pass = passWord;
		}
		
		public FreebaseClient( string userName, string passWord, bool useSandbox )
			:this( userName, passWord )
		{
			this._useSandbox = useSandbox;
		}

		public string Read(string query)
		{
			if( string.IsNullOrEmpty( query ) ){
				logger.Error( "A null query was passed to FreebaseClient.Read" );
				throw new ArgumentNullException("query" );
				
			}
			
			string url = CreateUrl( query );
			
			HttpWebRequest request = null;

			try{
				request = (HttpWebRequest)System.Net.WebRequest.Create(url);
			}
			catch{
				logger.Error( "FreeBaseReader.Ask->Creating Request Failed" );
				throw;//FIXME
			}
			
			request.Method = "GET";
			request.ContentType = "application/x-www-form-urlencoded";
			request.CookieContainer = authCookies;
			
			HttpWebResponse response = null;
			try{
				response = (HttpWebResponse)request.GetResponse();
			}
			catch{
				Console.WriteLine("FreeBaseReader.Ask->GetResponse Failed" );
				throw; //FIXME
			}
			string readString = GetStringFromResponse( response );
			response.Close();

			return readString;
		}
		
		private string CreateUrl( string query )
		{
			string url =
				(_useSandbox?sandbox:server) +
				queryurl +
				"?query=" + System.Web.HttpUtility.UrlDecode(query);
			Console.WriteLine( "FreeBaseReader.CreatUrl(string) -> url : "+ url );
			return url;
		}
		
		private string GetStringFromResponse( HttpWebResponse response )
		{
			
			StreamReader reader = new StreamReader(response.GetResponseStream());

			string readString = reader.ReadToEnd();
			reader.Close();
			
			return readString;
		}

		/// <summary>
		/// Authentication.
		/// </summary>
		public void Authenticate()
		{
			string authURI = (_useSandbox?sandbox:server) + path;
			Console.WriteLine( "FreeBaseReader.Authenticate()->authURI : " + authURI );

			// Create the web request body:

			string body = string.Format("username={0}&password={1}", user, pass);
			byte[] bytes = Encoding.UTF8.GetBytes( body );

			// Create the web request:

			HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create( authURI );
			request.Method = "POST";
			request.ContentType = "application/x-www-form-urlencoded";
			request.CookieContainer = new CookieContainer();
			request.ContentLength = bytes.Length;

			// Create the web request content stream:
			using ( Stream stream = request.GetRequestStream() )
			{
				stream.Write( bytes, 0, bytes.Length );
				stream.Close();
			}

			// Get the response & store the authentication cookies:
			HttpWebResponse response = null;
			try{
				response = (HttpWebResponse)request.GetResponse();
			}catch{
				
			}
			

			if ( response.Cookies.Count < 2 )
				throw new AuthenticationException( "Login failed. Is the login / password correct?" );

			authCookies = new CookieContainer();
			foreach ( Cookie myCookie in response.Cookies )
			{
				logger.Debug( "FreeBaseReader.Authenticate()->Adding Cookie : " + myCookie.Name);
				authCookies.Add(myCookie);
			}

			response.Close();
		}
	}
}
